package com.stp.yupao.utils;

import io.swagger.models.auth.In;

import java.util.*;

public class JaccardUserRecommender {
    private Map<Long, Set<String>> userTags;

    public JaccardUserRecommender() {
        this.userTags = new HashMap<>();
    }

    // 添加用户标签
    public void addUserTags(Long userId, Set<String> tags) {
        userTags.merge(userId, tags, (oldTags, newTags) -> {
            oldTags.addAll(newTags);
            return oldTags;
        });
    }

    // 计算Jaccard相似度
    private double jaccardSimilarity(Set<String> set1, Set<String> set2) {
        Set<String> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);

        Set<String> union = new HashSet<>(set1);
        union.addAll(set2);

        return union.isEmpty() ? 0.0 : (double) intersection.size() / union.size();
    }

    // 推荐相似用户
    public List<Long> recommendUsers(Long targetUserId, Integer topN, Set<Long> excludedUsers) {
        if (!userTags.containsKey(targetUserId)) {
            return Collections.emptyList();
        }

        Set<String> targetTags = userTags.get(targetUserId);
        PriorityQueue<UserScore> pq = new PriorityQueue<>(topN, Comparator.comparingDouble(UserScore::getScore));

        for (Map.Entry<Long, Set<String>> entry : userTags.entrySet()) {
            Long userId = entry.getKey();
            if (userId == targetUserId || excludedUsers.contains(userId)) {
                continue;
            }

            double similarity = jaccardSimilarity(targetTags, entry.getValue());

            if (pq.size() < topN) {
                pq.offer(new UserScore(userId, similarity));
            } else if (similarity > pq.peek().getScore()) {
                pq.poll();
                pq.offer(new UserScore(userId, similarity));
            }
        }

        List<Long> recommendations = new ArrayList<>(topN);
        while (!pq.isEmpty()) {
            recommendations.add(0, pq.poll().getUserId());
        }

        return recommendations;
    }
}
